import os

import pygame, math
from pygame.locals import *

import gummworld2

import data
import sprite
import spritesheet
import vec2d
import weapons
import jukebox
import settings

player = None

class Player(sprite.Sprite):
    speed = settings.player_speed

    def __init__(self, position, *groups):
        # image anim frames
        image_file = data.filepath(os.path.join('image','player0_b.png'))
        ss = spritesheet.SpriteSheet(image_file, True)
        self.images = ss.load_strip((64,64), 9, margin=(0,0), padding=(0,0.5), colorkey=-1, orient='v')
        self.frames = (0,1,2,3,4,5,6,7,8)
        self.image = self.images[8]
        self.time = 0.0
        self.facing = 0    
        
        # invoke the superclass
        self._position = vec2d.Vec2d(position)
        self._prev_pos = vec2d.Vec2d(position)
        super(Player, self).__init__(
            *groups,
            source=self.image
        )
        # Parent class derives rect from image. Hack it down for collisions.
        # Create a utility rect for drawing.
        self.rect.width = 15
        self.blit_rect = Rect(self.rect)
        
        self.rect.height = 15
        
        self.position = position
#        self.image.fill(pygame.Color('white'))
        
        global player
        player = self
        
        self.health = settings.player_inital_health
        self.weapons = [
            weapons.BaseballBat(), weapons.Pistol(),
            weapons.Chainsaw(), weapons.Shotgun(),
        ]
        self.melee_weapon = self.weapons[0]
        self.ranged_weapon = self.weapons[1]
        self.reeltimer = 0.
        
        jukebox.jukebox.load_sound(
            os.path.join(data.filepath('sound'), 'sfxr_01', '06.wav'),
            'player attack')
    
    @property
    def position(self):
        return self._position
    @position.setter
    def position(self, val):
        if val != self._prev_pos:
            pp = self._prev_pos
            pp.x,pp.y = self.position
        
        p = self._position
        p.x,p.y = val
        self.rect.center = round(p.x), round(p.y)
    
    def hurt(self, who, amount):
        self.health -= amount
        # TODO: make this a state machine like the zombies
        self.reeltimer = 0.4
        dx, dy = who.x - self._position.x, who.y - self._position.y
        d = math.sqrt(dx ** 2 + dy ** 2)
        self.vx, self.vy = -dx * 200. / d, -dy * 200. / d
    
    def in_melee_range(self, target_point):
        distance = gummworld2.geometry.distance(self.rect.center, target_point)
        return distance <= self.melee_weapon.max_range
    
    def in_long_range(self, target_point):
        distance = gummworld2.geometry.distance(self.rect.center, target_point)
        return distance <= self.ranged_weapon.max_range
    
    def melee_attack(self, other, attack_name='default'):
        return self.attack(other, self.melee_weapon, attack_name)
    
    def ranged_attack(self, other, attack_name='default'):
        return self.attack(other, self.ranged_weapon, attack_name)
    
    def attack(self, others, weapon, attack_name='default'):
        hits = weapon.attack(others, attack_name)
        if hits:
            jukebox.jukebox['player attack'].play()
        return hits
    
    def equip_next_weapon(self, type_):
        if type_ not in ('melee','ranged'):
            raise pygame.error,'arg1 must be "melee" or "ranged"; got '+str(type_)
        which_weapon = type_ + '_weapon'
        my_weapon = getattr(self, which_weapon)
        if my_weapon is None or my_weapon.state in ('ready','empty'):
            i = self.weapons.index(getattr(self, which_weapon))
            weaps = self.weapons[i+1:] + self.weapons[:i]
            for weap in weaps:
                if weap.type == type_:
                    setattr(self, which_weapon, weap)
                    break
    
    def think(self, dt):
        self.melee_weapon.think(dt)
        self.ranged_weapon.think(dt)
        if self.reeltimer: self.reeltimer = max(self.reeltimer - dt, 0.)
        self._update_animation(dt)
    
    def _update_animation(self, dt):
        if self.position != self._prev_pos:
            self.time += dt
            # number of images
            n_frames = len(self.frames) - 1
            # compute frame index from current time slice
            n = int(round(self.time % 1.0 * n_frames))
            frame = self.frames[n]
        else:
            self.time = 0.0
            frame = 8
        self.image = self.images[frame]
        # compute image rotation and scale
#        angle = 360 - round(self.facing/45.0) * 45
        angle = 360 - self.facing
        self.image = pygame.transform.rotozoom(self.image, angle, .75)
        # compute the drawing rect
        self.blit_rect.size = self.image.get_size()
        self.blit_rect.center = self.rect.center

    def setmotion(self, m):
        if not self.reeltimer:
            mx = (m[K_RIGHT] or m[K_d] or m[K_e]) - (m[K_LEFT] or m[K_a])
            my = (m[K_DOWN] or m[K_s] or m[K_o]) - (m[K_UP] or m[K_w] or m[K_COMMA])

            if mx and my:
                mx *= 0.707
                my *= 0.707
    
            self.vx = mx * self.speed
            self.vy = my * self.speed
